| Conditions | 59 |
| Total Lines | 391 |
| Code Lines | 199 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like egw_action_dragdrop.js ➔ egwDragActionImplementation often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | /** |
||
| 76 | function egwDragActionImplementation() |
||
| 77 | { |
||
| 78 | var ai = new egwActionImplementation(); |
||
| 79 | |||
| 80 | ai.type = "drag"; |
||
| 81 | |||
| 82 | ai.helper = null; |
||
| 83 | ai.ddTypes = []; |
||
| 84 | ai.selected = []; |
||
| 85 | |||
| 86 | // Define default helper DOM |
||
| 87 | // default helper also can be called later in application code in order to customization |
||
| 88 | ai.defaultDDHelper = function (_selected) |
||
| 89 | { |
||
| 90 | // Table containing clone of rows |
||
| 91 | var table = jQuery(document.createElement("table")).addClass('egwGridView_grid et2_egw_action_ddHelper_row'); |
||
| 92 | // tr element to use as last row to show lable more ... |
||
| 93 | var moreRow = jQuery(document.createElement('tr')).addClass('et2_egw_action_ddHelper_moreRow'); |
||
| 94 | // Main div helper container |
||
| 95 | var div = jQuery(document.createElement("div")).append(table); |
||
| 96 | |||
| 97 | var rows = []; |
||
| 98 | // Maximum number of rows to show |
||
| 99 | var maxRows = 3; |
||
| 100 | // item label |
||
| 101 | var itemLabel = egw.lang(egw.link_get_registry(egw.app_name(),_selected.length > 1?'entries':'entry')||egw.app_name()); |
||
| 102 | |||
| 103 | var index = 0; |
||
| 104 | |||
| 105 | // Take select all into account when counting number of rows, because they may not be |
||
| 106 | // in _selected object |
||
| 107 | var pseudoNumRows = (_selected[0] && _selected[0]._context && _selected[0]._context._selectionMgr && |
||
| 108 | _selected[0]._context._selectionMgr._selectAll) ? |
||
| 109 | _selected[0]._context._selectionMgr._total : _selected.length; |
||
| 110 | |||
| 111 | for (var i = 0; i < _selected.length;i++) |
||
| 112 | { |
||
| 113 | var row = jQuery(_selected[i].iface.getDOMNode()).clone(); |
||
| 114 | if (row) |
||
| 115 | { |
||
| 116 | rows.push(row); |
||
| 117 | table.append(row); |
||
| 118 | } |
||
| 119 | index++; |
||
| 120 | if (index == maxRows) |
||
| 121 | { |
||
| 122 | // Lable to show number of items |
||
| 123 | var spanCnt = jQuery(document.createElement('span')) |
||
| 124 | .addClass('et2_egw_action_ddHelper_itemsCnt') |
||
| 125 | .appendTo(div); |
||
| 126 | |||
| 127 | spanCnt.text(pseudoNumRows +' '+ itemLabel); |
||
| 128 | // Number of not shown rows |
||
| 129 | var restRows = pseudoNumRows - maxRows; |
||
| 130 | if (restRows) |
||
| 131 | { |
||
| 132 | moreRow.text((pseudoNumRows - maxRows) +' '+egw.lang('more %1 selected ...', itemLabel)); |
||
| 133 | } |
||
| 134 | table.append(moreRow); |
||
| 135 | break; |
||
| 136 | } |
||
| 137 | } |
||
| 138 | |||
| 139 | var text = jQuery(document.createElement('div')).addClass('et2_egw_action_ddHelper_tip'); |
||
| 140 | div.append(text); |
||
| 141 | |||
| 142 | // Add notice of Ctrl key, if supported |
||
| 143 | if('draggable' in document.createElement('span') && |
||
| 144 | navigator && navigator.userAgent.indexOf('Chrome') >= 0 && egw.app_name() == 'filemanager') // currently only filemanager supports drag out |
||
| 145 | { |
||
| 146 | var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? |
||
| 147 | egw.lang('Alt') : egw.lang('Command ⌘'); |
||
| 148 | text.text(egw.lang('Hold [%1] and [%2] key to drag %3 to your desktop', key, egw.lang('Shift ⇧'), itemLabel)); |
||
| 149 | } |
||
| 150 | // Final html DOM return as helper structor |
||
| 151 | return div; |
||
| 152 | }; |
||
| 153 | |||
| 154 | ai.doRegisterAction = function(_aoi, _callback, _context) |
||
| 155 | { |
||
| 156 | var node = _aoi.getDOMNode(); |
||
| 157 | |||
| 158 | if (node) |
||
| 159 | { |
||
| 160 | // Prevent selection |
||
| 161 | node.onselectstart = function () { |
||
| 162 | return false; |
||
| 163 | }; |
||
| 164 | if (!(window.FileReader && 'draggable' in document.createElement('span')) ) |
||
| 165 | { |
||
| 166 | // No DnD support |
||
| 167 | return; |
||
|
|
|||
| 168 | } |
||
| 169 | |||
| 170 | // It shouldn't be so hard to get the action... |
||
| 171 | var action = null; |
||
| 172 | var groups = _context.getActionImplementationGroups(); |
||
| 173 | if(!groups.drag) return; |
||
| 174 | for(var i = 0; i < groups.drag.length; i++) |
||
| 175 | { |
||
| 176 | // dragType 'file' says it can be dragged as a file |
||
| 177 | if(groups.drag[i].link.actionObj.dragType == 'file' || groups.drag[i].link.actionObj.dragType.indexOf('file') > -1) |
||
| 178 | { |
||
| 179 | action = groups.drag[i].link.actionObj; |
||
| 180 | break; |
||
| 181 | } |
||
| 182 | } |
||
| 183 | if(action) |
||
| 184 | { |
||
| 185 | /** |
||
| 186 | * We found an action with dragType 'file', so by holding Ctrl |
||
| 187 | * key & dragging, user can drag from browser to system. |
||
| 188 | * The global data store must provide a full, absolute URL in 'download_url' |
||
| 189 | * and a mime in 'mime'. |
||
| 190 | * |
||
| 191 | * Unfortunately, Native DnD to drag the file conflicts with jQueryUI draggable, |
||
| 192 | * which handles all the other DnD actions. We get around this by: |
||
| 193 | * 1. Require the user indicate a file drag with Ctrl key |
||
| 194 | * 2. Disable jQueryUI draggable, then turn on native draggable attribute |
||
| 195 | * This way we can at least toggle which one is operating, so they |
||
| 196 | * both work alternately if not together. |
||
| 197 | */ |
||
| 198 | // Native DnD - Doesn't play nice with jQueryUI Sortable |
||
| 199 | // Tell jQuery to include this property |
||
| 200 | jQuery.event.props.push('dataTransfer'); |
||
| 201 | |||
| 202 | jQuery(node).off("mousedown") |
||
| 203 | .on("mousedown", function(event) { |
||
| 204 | var dragOut = _context.isDragOut(event); |
||
| 205 | jQuery(this).attr("draggable", dragOut? "true" : ""); |
||
| 206 | jQuery(node).draggable("option","disabled",dragOut); |
||
| 207 | if (dragOut) |
||
| 208 | { |
||
| 209 | // Disabling draggable adds some UI classes, but we don't care so remove them |
||
| 210 | jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled"); |
||
| 211 | |||
| 212 | } |
||
| 213 | else |
||
| 214 | { |
||
| 215 | if (_context.isSelection(event)) |
||
| 216 | { |
||
| 217 | jQuery(node).draggable("disable"); |
||
| 218 | // Disabling draggable adds some UI classes, but we don't care so remove them |
||
| 219 | jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled"); |
||
| 220 | } |
||
| 221 | else if(event.which != 3) |
||
| 222 | { |
||
| 223 | document.getSelection().removeAllRanges(); |
||
| 224 | } |
||
| 225 | if(!(dragOut) || !this.addEventListener) return; |
||
| 226 | } |
||
| 227 | }) |
||
| 228 | .on ("mouseup", function (event){ |
||
| 229 | if (_context.isSelection(event)) |
||
| 230 | jQuery(node).draggable("enable"); |
||
| 231 | }) |
||
| 232 | .on("dragstart", function(event) { |
||
| 233 | if(_context.isSelection(event)) return; |
||
| 234 | if(event.dataTransfer == null) { |
||
| 235 | return; |
||
| 236 | } |
||
| 237 | event.dataTransfer.effectAllowed="copy"; |
||
| 238 | |||
| 239 | // Get all selected |
||
| 240 | // Multiples aren't supported by event.dataTransfer, yet, so |
||
| 241 | // select only the row they clicked on. |
||
| 242 | // var selected = _context.getSelectedLinks('drag'); |
||
| 243 | var selected = [_context]; |
||
| 244 | _context.parent.setAllSelected(false); |
||
| 245 | _context.setSelected(true); |
||
| 246 | |||
| 247 | // Set file data |
||
| 248 | for(var i = 0; i < selected.length; i++) |
||
| 249 | { |
||
| 250 | var data = selected[i].data || egw.dataGetUIDdata(selected[i].id).data || {}; |
||
| 251 | if(data && data.mime && data.download_url) |
||
| 252 | { |
||
| 253 | var url = data.download_url; |
||
| 254 | |||
| 255 | // NEED an absolute URL |
||
| 256 | if (url[0] == '/') url = egw.link(url); |
||
| 257 | // egw.link adds the webserver, but that might not be an absolute URL - try again |
||
| 258 | if (url[0] == '/') url = window.location.origin+url; |
||
| 259 | |||
| 260 | // Unfortunately, dragging files is currently only supported by Chrome |
||
| 261 | if(navigator && navigator.userAgent.indexOf('Chrome')) |
||
| 262 | { |
||
| 263 | event.dataTransfer.setData("DownloadURL", data.mime+':'+data.name+':'+url); |
||
| 264 | } |
||
| 265 | else |
||
| 266 | { |
||
| 267 | // Include URL as a fallback |
||
| 268 | event.dataTransfer.setData("text/uri-list", url); |
||
| 269 | } |
||
| 270 | } |
||
| 271 | } |
||
| 272 | if(event.dataTransfer.types.length == 0) |
||
| 273 | { |
||
| 274 | // No file data? Abort: drag does nothing |
||
| 275 | event.preventDefault(); |
||
| 276 | return; |
||
| 277 | } |
||
| 278 | |||
| 279 | // Create drag icon |
||
| 280 | _callback.call(_context, _context, ai); |
||
| 281 | // Drag icon must be visible for setDragImage() - we'll remove it on drag |
||
| 282 | jQuery("body").append(ai.helper); |
||
| 283 | event.dataTransfer.setDragImage(ai.helper[0],-12,-12); |
||
| 284 | }) |
||
| 285 | .on("drag", function(e) { |
||
| 286 | // Remove the helper, it has been copied into the dataTransfer object now |
||
| 287 | // Hopefully user didn't notice it... |
||
| 288 | if(e.dataTransfer != null) |
||
| 289 | { |
||
| 290 | ai.helper.remove(); |
||
| 291 | } |
||
| 292 | }); |
||
| 293 | } |
||
| 294 | else |
||
| 295 | { |
||
| 296 | // Use Ctrl key in order to select content |
||
| 297 | jQuery(node).off("mousedown") |
||
| 298 | .on({ |
||
| 299 | mousedown: function(event){ |
||
| 300 | if (_context.isSelection(event)){ |
||
| 301 | jQuery(node).draggable("disable"); |
||
| 302 | // Disabling draggable adds some UI classes, but we don't care so remove them |
||
| 303 | jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled"); |
||
| 304 | } |
||
| 305 | else if(event.which != 3) |
||
| 306 | { |
||
| 307 | document.getSelection().removeAllRanges(); |
||
| 308 | } |
||
| 309 | }, |
||
| 310 | mouseup: function (){ |
||
| 311 | jQuery(node).draggable("enable"); |
||
| 312 | // Set cursor back to auto. Seems FF can't handle cursor reversion |
||
| 313 | jQuery('body').css({cursor:'auto'}); |
||
| 314 | } |
||
| 315 | }); |
||
| 316 | } |
||
| 317 | jQuery(node).draggable( |
||
| 318 | { |
||
| 319 | "distance": 20, |
||
| 320 | "cursor": "move", |
||
| 321 | "cursorAt": { top: -12, left: -12 }, |
||
| 322 | "helper": function(e) { |
||
| 323 | // The helper function is called before the start function |
||
| 324 | // is evoked. Call the given callback function. The callback |
||
| 325 | // function will gather the selected elements and action links |
||
| 326 | // and call the doExecuteImplementation function. This |
||
| 327 | // will call the onExecute function of the first action |
||
| 328 | // in order to obtain the helper object (stored in ai.helper) |
||
| 329 | // and the multiple dragDropTypes (ai.ddTypes) |
||
| 330 | _callback.call(_context, false, ai); |
||
| 331 | |||
| 332 | jQuery(node).data("ddTypes", ai.ddTypes); |
||
| 333 | jQuery(node).data("selected", ai.selected); |
||
| 334 | |||
| 335 | if (ai.helper) |
||
| 336 | { |
||
| 337 | // Add a basic class to the helper in order to standardize the background layout |
||
| 338 | ai.helper.addClass('et2_egw_action_ddHelper'); |
||
| 339 | |||
| 340 | // Append the helper object to the body element - this |
||
| 341 | // fixes a bug in IE: If the element isn't inserted into |
||
| 342 | // the DOM-tree jquery appends it to the parent node. |
||
| 343 | // In case this is a table it doesn't work correctly |
||
| 344 | jQuery("body").append(ai.helper); |
||
| 345 | return ai.helper; |
||
| 346 | } |
||
| 347 | |||
| 348 | // Return an empty div if the helper dom node is not set |
||
| 349 | return ai.defaultDDHelper(ai.selected);//jQuery(document.createElement("div")).addClass('et2_egw_action_ddHelper'); |
||
| 350 | }, |
||
| 351 | "start": function(e) { |
||
| 352 | return ai.helper != null; |
||
| 353 | }, |
||
| 354 | revert: function(valid) |
||
| 355 | { |
||
| 356 | var dTarget = this; |
||
| 357 | if (!valid) |
||
| 358 | { |
||
| 359 | // Tolerance value of pixels arround the draggable target |
||
| 360 | // to distinguish whether the action was intended for dragging or selecting content. |
||
| 361 | var tipTelorance = 10; |
||
| 362 | var helperTop = ai.helper.position().top; |
||
| 363 | |||
| 364 | if (helperTop >= dTarget.offset().top |
||
| 365 | && helperTop <= (dTarget.height() + dTarget.offset().top) + tipTelorance) |
||
| 366 | { |
||
| 367 | var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? |
||
| 368 | egw.lang("Ctrl") : egw.lang("Command ⌘"); |
||
| 369 | // We can not use Ctrl key for FF because FF has specific function |
||
| 370 | // for element selection bound to ctrl key and it would confilicts |
||
| 371 | // with our selection functionallity. Therefore, we use Alt key when |
||
| 372 | // it comes to FF regardless of OS. |
||
| 373 | if (window.navigator.userAgent.match(/firefox/i)) key = egw.lang("Alt"); |
||
| 374 | egw.message(egw.lang('Hold [%1] key to select text eg. to copy it', key), 'info'); |
||
| 375 | } |
||
| 376 | |||
| 377 | // Invalid target |
||
| 378 | return true; |
||
| 379 | } |
||
| 380 | else |
||
| 381 | { |
||
| 382 | // Valid target |
||
| 383 | return false; |
||
| 384 | } |
||
| 385 | }, |
||
| 386 | // Solves problem with scroll position changing in the grid |
||
| 387 | // component |
||
| 388 | "refreshPositions": true, |
||
| 389 | "scroll": false, |
||
| 390 | //"containment": "document", |
||
| 391 | "iframeFix": true, |
||
| 392 | "delay": 300 |
||
| 393 | } |
||
| 394 | ); |
||
| 395 | |||
| 396 | |||
| 397 | return true; |
||
| 398 | } |
||
| 399 | return false; |
||
| 400 | }; |
||
| 401 | |||
| 402 | ai.doUnregisterAction = function(_aoi) |
||
| 403 | { |
||
| 404 | var node = _aoi.getDOMNode(); |
||
| 405 | |||
| 406 | if (node && jQuery(node).data("uiDraggable")){ |
||
| 407 | jQuery(node).draggable("destroy"); |
||
| 408 | } |
||
| 409 | }; |
||
| 410 | |||
| 411 | /** |
||
| 412 | * Builds the context menu and shows it at the given position/DOM-Node. |
||
| 413 | * |
||
| 414 | * @param {string} _context |
||
| 415 | * @param {array} _selected |
||
| 416 | * @param {object} _links |
||
| 417 | */ |
||
| 418 | ai.doExecuteImplementation = function(_context, _selected, _links) |
||
| 419 | { |
||
| 420 | // Reset the helper object of the action implementation |
||
| 421 | this.helper = null; |
||
| 422 | var hasLink = false; |
||
| 423 | |||
| 424 | // Store the drag-drop types |
||
| 425 | this.ddTypes = []; |
||
| 426 | this.selected = _selected; |
||
| 427 | |||
| 428 | // Call the onExecute event of the first actionObject |
||
| 429 | for (var k in _links) |
||
| 430 | { |
||
| 431 | if (_links[k].visible) |
||
| 432 | { |
||
| 433 | hasLink = true; |
||
| 434 | |||
| 435 | // Only execute the following code if a JS function is registered |
||
| 436 | // for the action and this is the first action link |
||
| 437 | if (!this.helper && _links[k].actionObj.onExecute.hasHandler()) |
||
| 438 | { |
||
| 439 | this.helper = _links[k].actionObj.execute(_selected); |
||
| 440 | } |
||
| 441 | |||
| 442 | // Push the dragType of the associated action object onto the |
||
| 443 | // drag type list - this allows an element to support multiple |
||
| 444 | // drag/drop types. |
||
| 445 | var type = jQuery.isArray(_links[k].actionObj.dragType) ? _links[k].actionObj.dragType : [_links[k].actionObj.dragType]; |
||
| 446 | for(var i = 0; i < type.length; i++) |
||
| 447 | { |
||
| 448 | if (this.ddTypes.indexOf(type[i]) == -1) |
||
| 449 | { |
||
| 450 | this.ddTypes.push(type[i]); |
||
| 451 | } |
||
| 452 | } |
||
| 453 | } |
||
| 454 | } |
||
| 455 | |||
| 456 | // If no helper has been defined, create an default one |
||
| 457 | if (!this.helper && hasLink) |
||
| 458 | { |
||
| 459 | this.helper = ai.defaultDDHelper(_selected); |
||
| 460 | } |
||
| 461 | |||
| 462 | return true; |
||
| 463 | }; |
||
| 464 | |||
| 465 | return ai; |
||
| 466 | } |
||
| 467 | |||
| 724 |